package com.quantum.util
{

	import com.quantum.logging.LogFactory;

	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.geom.Matrix;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.utils.Dictionary;

	import mx.containers.accordionClasses.AccordionHeader;
	import mx.controls.tabBarClasses.Tab;
	import mx.core.BitmapAsset;
	import mx.core.UIComponent;
	import mx.logging.ILogger;
	import mx.logging.LogEventLevel;

	/**
	 * Provides a workaround for using run-time loaded graphics in styles and properties which require a Class reference
	 */
	public class IconUtils extends BitmapAsset
	{

		private static var dictionary:Dictionary;

		private static var imageMap:Dictionary;

		private static var log:ILogger=LogFactory.getLogger(IconUtils);

		/**
		 * Used to associate run-time graphics with a target
		 * @param target A reference to the component associated with this icon
		 * @param source A url to a JPG, PNG or GIF file you wish to be loaded and displayed
		 * @param width Defines the width of the graphic when displayed
		 * @param height Defines the height of the graphic when displayed
		 * @return A reference to the IconUtility class which may be treated as a BitmapAsset
		 * @example &lt;mx:Button id="button" icon="{IconUtility.getClass(button, 'http://www.yourdomain.com/images/test.jpg')}" /&gt;
		 */
		public static function getClass(target:Object, source:String, width:Number=16, height:Number=16):Class
		{
			if (!dictionary)
			{
				dictionary=new Dictionary(true);
				imageMap=new Dictionary(true);
			}

			var loader:Loader=null;
			if (!imageMap[source])
			{
				loader=new Loader();
				loader.load(new URLRequest(source as String), new LoaderContext(true));
				loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
				imageMap[source]={loader: loader, bitmap: undefined, width: width, height: height};
			}
			dictionary[target]={source: source};
			return IconUtils;
		}

		/**
		 * @private
		 */
		public function IconUtils():void
		{
			addEventListener(Event.ADDED, addedHandler)
		}

		private function addedHandler(event:Event):void
		{
			if (parent)
			{
				if (dictionary[parent])
				{
					getData(parent);
				}
				else if (parent.hasOwnProperty("data"))
				{
					var item:Object=parent["data"];
					getData(item);
				}
			}
		}

		private function getData(object:Object):void
		{
			var data:*=dictionary[object];
			if (data)
			{
				var sourceData:*=data.source;
				var bitData:*=imageMap[sourceData]
				if (bitData)
				{
					if (bitData.bitmap)
					{
						bitmapData=bitData.bitmap;
						return;
					}
					else
					{
						bitmapData=new BitmapData(bitData.width, bitData.height, true, 0);
						bitData.bitmap=bitmapData;
					}
					var loader:Loader=bitData.loader as Loader;
					if (loader)
					{
						if (!loader.content)
						{
							loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
						}
						else
						{
							displayLoader(loader);
						}
					}
				}
			}
		}

		private function displayLoader(loader:Loader):void
		{
			if (!bitmapData)
			{
				bitmapData=new BitmapData(loader.content.width, loader.content.height, true, 0);
			}
			bitmapData.draw(loader, new Matrix(bitmapData.width / loader.width, 0, 0, bitmapData.height / loader.height, 0, 0));
			if (loader.hasEventListener(Event.COMPLETE))
			{
				loader.removeEventListener(Event.COMPLETE, completeHandler);
			}
			if (parent is UIComponent)
			{
				var component:UIComponent=parent as UIComponent;
				component.invalidateSize();
				removeEventListener(Event.ADDED, addedHandler);
			}
		}

		private function completeHandler(event:Event):void
		{
			if (event && event.target && event.target is LoaderInfo)
			{
				displayLoader(event.target.loader as Loader);
			}
		}

		private static function ioErrorListener(event:IOErrorEvent):void
		{
			log.log(LogEventLevel.WARN, event.text);
		}
	}
}